package com.fang.dubbo.mock.rpc.netty;

import com.fang.dubbo.mock.rpc.protocol.Invocation;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

/**
 * @author fanglingxiao
 * @version 1.0
 * @description 内部方法调用顺讯
 * channelActive -> NettyClientHandler.setParam -> call -> channelRead -> call
 * @date 2022/1/2 1:13 下午
 **/
@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NettyClientHandler extends ChannelHandlerAdapter implements Callable {
    // 上下文
    private ChannelHandlerContext context;
    // 返回结果
    private Object result;
    // 参数
    private Invocation param;

    /**
     * 与服务器创建连接后就会被调用
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("client channelActive 被调用");
        context = ctx;
    }

    /**
     * 收到服务器请求后，调用该方法
     */
    @Override
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("client channelRead 被调用");
        result = msg;
        // 唤醒等待的线程
        notify();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }

    /**
     * 被代理对象调用，发送数据给服务器，wait等待被channelRead唤醒 再返回结果
     */
    @Override
    public synchronized Object call() throws Exception {
        log.info("client call 被调用1");
        context.writeAndFlush(param);
        // 进行wait,等待NettyServerHandler返回结果，channelRead获取结果后唤醒
        wait();
        log.info("client call 被调用2");
        return result;
    }
}
